using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Magiq.Support;
using Magiq.Update;

namespace Magiq.Sql {
  public class TableUpdate<T> {
    private readonly LambdaExpression where;
    private readonly string whereParameter;
    private readonly IQueryable<T> whereQuery;
    private bool? isWhereInvalidator;

    public TableUpdate(IQueryable<T> whereQuery) {
      this.whereQuery = whereQuery;
      where = whereQuery.Expression as LambdaExpression;
      if (where == null) {
        var memberCall = whereQuery.Expression as MethodCallExpression;
        if (memberCall != null && memberCall.Arguments.Count == 2) {
          var unary = memberCall.Arguments[1] as UnaryExpression;
          if (unary != null)
            where = unary.Operand as LambdaExpression;
        }

        if (where == null)
          throw new NotSupportedException("I don't know how to get the lambda expression from " +
                                          whereQuery.Expression);
      }
      whereParameter = where.Parameters.Single().Name;
      PropertySets = new List<IPropertySet>();
    }

    public bool IsWhereInvalidation {
      get {
        if (!isWhereInvalidator.HasValue)
          isWhereInvalidator = PropertySets.Any(IsWhereInvalidating);
        return isWhereInvalidator.Value;
      }
    }

    public List<IPropertySet> PropertySets { get; private set; }

    public IQueryable<T> Where {
      get { return whereQuery; }
    }

    public void Set(IPropertySet set) {
      PropertySets.Add(set);
    }

    private bool IsWhereInvalidating(IPropertySet set) {
      var propertyParameter = where.Parameters.Single().Name;
      var stringToFind = set.PropertyExpression.ToString()
        .From("=>")
        .Replace(propertyParameter + ".", whereParameter + ".").Trim();

      return where.ToString().Contains(stringToFind);
    }
  }
}